package top.onedream.buildsmallsoftware.util

import com.fasterxml.jackson.databind.ObjectMapper
import org.springframework.beans.factory.annotation.Value
import org.springframework.stereotype.Component
import top.onedream.buildsmallsoftware.model.user.LoginUser
import top.onedream.buildsmallsoftware.model.user.User
import java.util.concurrent.TimeUnit
import javax.servlet.http.HttpServletRequest

/**
 * 令牌工具类
 * @author zhangkein
 * @date 2023/05/16
 * @constructor 创建[TokenUtil]
 * @param [objectMapper] 对象映射器
 * @param [redisCache] 复述,缓存
 * @param [httpServletRequest] http servlet请求
 */
@Component
class TokenUtil(
    private val objectMapper: ObjectMapper,
    private val redisCache: RedisCache,
    private val httpServletRequest: HttpServletRequest
) {

    /**
     * 到期时间
     */
    @Value("\${jwt.expiration}")//An annotation argument must be a compile-time constant
    private val expireTime = 0

    /**
     * 秘密
     * */
    @Value("\${jwt.secret}")
    private val secret: String? = null

    /**
     * 令牌头
     */
    @Value("\${jwt.tokenHeader}")
    private val tokenHeader: String? = null

    /**
     * 令牌头
     * */
    @Value("\${jwt.tokenHead}")
    private val tokenHead: String? = null

    /** 一分钟 */
    private val MINUTE = 60 * 1000


    fun getLoginUser(request: HttpServletRequest): User? {
        // 获取请求携带的令牌
        val headToken = request.getHeader(tokenHeader) // 获取头中token
        // 验证是否为空，格式是否满足预定要求
        if (headToken != null && headToken.startsWith(tokenHead!!)) {
            val token = headToken.substring(7)
            val map: Map<String, Any> = JwtUtil.parseJWT(token, secret!!) // 掉用jwt解密方法解密
            val value = map["user"] as String
            val user = objectMapper.readValue(value, User::class.java)
            val target: LoginUser = redisCache.getCacheObject("loginUser:" + user.id)
            if (target.ipAddress != WebUtils.getIpAddr(request)) {
                return null
            }
            refreshToken(target)
            TokenHolder.setTokenFromRequest(user)
            return user;
        }
        return null
    }

    fun refreshToken(user: LoginUser) {
        if (user.expireTime!! < System.currentTimeMillis() + expireTime * MINUTE / 3) {
            refreshToken(user.user!!)
        }
    }


    fun createToken(user: User): String? {
        refreshToken(user)
        return tokenHead + JwtUtil.createJwt(user, secret!!)
    }

    fun refreshToken(user: User) {
        val loginUser = LoginUser()
        loginUser.user = user
        loginUser.loginTime = System.currentTimeMillis()
        loginUser.expireTime = loginUser.loginTime!! + expireTime * MINUTE
        loginUser.ipAddress = WebUtils.getIpAddr(httpServletRequest)
        redisCache.setCacheObject("loginUser:" + user.id, loginUser, expireTime, TimeUnit.MINUTES)
    }
}